package com.carey.blog.jsonrpc.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.carey.blog.action.StatusCodes;
import com.carey.blog.framework.latke.Keys;
import com.carey.blog.framework.latke.action.ActionException;
import com.carey.blog.framework.latke.repository.Query;
import com.carey.blog.framework.latke.repository.RepositoryException;
import com.carey.blog.jsonrpc.AbstractGAEJSONRpcService;
import com.carey.blog.model.Tag;
import com.carey.blog.repository.TagRepository;
import com.carey.blog.repository.impl.TagGAERepository;
import com.carey.blog.util.Users;

/**
 * Tag service for JavaScript client.
 * 
 */
public final class TagService extends AbstractGAEJSONRpcService {

	/**
	 * Logger.
	 */
	private static final Logger LOGGER = Logger.getLogger(TagService.class
			.getName());
	/**
	 * Tag repository.
	 */
	private TagRepository tagRepository = TagGAERepository.getInstance();
	/**
	 * User utilities.
	 */
	private Users userUtils = Users.getInstance();

	/**
	 * Gets all unused tags.
	 * 
	 * @param request
	 *            the specified http servlet request
	 * @param response
	 *            the specified http servlet response
	 * @return for example,
	 * 
	 *         <pre>
	 * [
	 *     {"tagTitle": "tag1", "tagReferenceCount": 0},
	 *     {"tagTitle": "tag2", "tagReferenceCount": 0},
	 *     ....
	 * ]
	 * </pre>
	 * 
	 *         , returns an empty if not found
	 * @throws ActionException
	 *             action exception
	 * @throws IOException
	 *             io exception
	 */
	public List<JSONObject> getUnusedTags(final HttpServletRequest request,
			final HttpServletResponse response) throws ActionException,
			IOException {
		final List<JSONObject> ret = new ArrayList<JSONObject>();
		if (!userUtils.isLoggedIn()) {
			response.sendError(HttpServletResponse.SC_FORBIDDEN);
			return ret;
		}
		final JSONArray tags = getTags(request, response);

		try {
			for (int i = 0; i < tags.length(); i++) {
				final JSONObject tag = tags.getJSONObject(i);
				final int tagRefCnt = tag.getInt(Tag.TAG_REFERENCE_COUNT);
				if (0 == tagRefCnt) {
					ret.add(tag);
				}
			}
		} catch (final Exception e) {
			LOGGER.log(Level.SEVERE, "Remove unused tags fail: {0}",
					e.getMessage());
		}

		return ret;
	}

	/**
	 * Removes all unused tags.
	 * 
	 * @param request
	 *            the specified http servlet request
	 * @param response
	 *            the specified http servlet response
	 * @return for example,
	 * 
	 *         <pre>
	 * {
	 *     "sc": "REMOVE_UNUSED_TAGS_SUCC"
	 * }
	 * </pre>
	 * @throws ActionException
	 *             action exception
	 * @throws IOException
	 *             io exception
	 */
	public JSONObject removeUnusedTags(final HttpServletRequest request,
			final HttpServletResponse response) throws ActionException,
			IOException {
		final JSONObject ret = new JSONObject();
		if (!userUtils.isAdminLoggedIn()) {
			response.sendError(HttpServletResponse.SC_FORBIDDEN);
			return ret;
		}
		final JSONArray tags = getTags(request, response);

		try {
			for (int i = 0; i < tags.length(); i++) {
				final JSONObject tag = tags.getJSONObject(i);
				final int tagRefCnt = tag.getInt(Tag.TAG_REFERENCE_COUNT);
				if (0 == tagRefCnt) {
					final String tagId = tag.getString(Keys.OBJECT_ID);
					tagRepository.remove(tagId);
				}
			}

			ret.put(Keys.STATUS_CODE, StatusCodes.REMOVE_UNUSED_TAGS_SUCC);

		} catch (final Exception e) {
			LOGGER.log(Level.SEVERE, "Remove unused tags fail: {0}",
					e.getMessage());

			try {
				ret.put(Keys.STATUS_CODE, StatusCodes.REMOVE_UNUSED_TAGS_FAIL_);
			} catch (final JSONException ex) {
				LOGGER.severe(ex.getMessage());
				throw new ActionException(e);
			}
		}

		return ret;
	}

	/**
	 * Gets all tags.
	 * 
	 * @param request
	 *            the specified http servlet request
	 * @param response
	 *            the specified http servlet response
	 * @return for example,
	 * 
	 *         <pre>
	 * [
	 *     {"tagTitle": "", "tagReferenceCount": int},
	 *     ....
	 * ]
	 * </pre>
	 * @throws ActionException
	 *             action exception
	 * @throws IOException
	 *             io exception
	 */
	public JSONArray getTags(final HttpServletRequest request,
			final HttpServletResponse response) throws ActionException,
			IOException {
		JSONArray ret = new JSONArray();
		if (!userUtils.isLoggedIn()) {
			response.sendError(HttpServletResponse.SC_FORBIDDEN);
			return ret;
		}

		try {
			final JSONObject result = tagRepository.get(new Query());
			final JSONArray tagArray = result.optJSONArray(Keys.RESULTS);
			if (null != tagArray) {
				ret = tagArray;
			}
		} catch (final RepositoryException e) {
			LOGGER.log(Level.SEVERE, e.getMessage(), e);
		}

		return ret;
	}

	/**
	 * Gets the {@link TagService} singleton.
	 * 
	 * @return the singleton
	 */
	public static TagService getInstance() {
		return SingletonHolder.SINGLETON;
	}

	/**
	 * Private default constructor.
	 */
	private TagService() {
	}

	/**
	 * Singleton holder.
	 * 
	 */
	private static final class SingletonHolder {

		/**
		 * Singleton.
		 */
		private static final TagService SINGLETON = new TagService();

		/**
		 * Private default constructor.
		 */
		private SingletonHolder() {
		}
	}
}
